#include <jni.h>
#include <string>
#include "FFPlayer.h"
#include <android/native_window_jni.h> // ANativeWindow 用来渲染画面的 == Surface对象

extern "C" {
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
}

// 加载JavaVM
JavaVM *vm;
// 渲染视频用
ANativeWindow *window = nullptr;
pthread_mutex_t mutex = PTHREAD_COND_INITIALIZER; // 静态初始化

// 系统调用，jni加载回调
jint JNI_OnLoad(JavaVM *vm, void *args) {
    ::vm = vm;
    return JNI_VERSION_1_6;
}

/**
 * 1. native层 VideoPlayer对象创建
 */
extern "C"
JNIEXPORT jlong JNICALL
Java_com_boardour_ffmpegdemo_player_FFPlayer_n_1videoPlayer(JNIEnv *env, jobject thiz) {
    return reinterpret_cast<jlong>(new FFPlayer());
}

/**
 * 视频数据 解析成RGBA后的回调方法
 * @param data  RGBA数据
 * @param width 宽
 * @param height 高
 * @param lineSize 行
 */
void renderCallback(uint8_t *data, int width, int height, int lineSize) {
    pthread_mutex_lock(&mutex);
    if (!window) {
        pthread_mutex_unlock(&mutex); // 出现了问题后，必须考虑到，释放锁，怕出现死锁问题
        return;
    }
    // 设置窗口的大小，各个属性
    ANativeWindow_setBuffersGeometry(window, width, height, WINDOW_FORMAT_RGBA_8888);
    ANativeWindow_Buffer buffer;
    int r = ANativeWindow_lock(window, &buffer, nullptr);
    if (r != 0) {
        ANativeWindow_release(window);
        window = nullptr;
        pthread_mutex_unlock(&mutex); // 出现了问题后，必须考虑到，释放锁，怕出现死锁问题
        return;
    }
    // TODO 开始真正的渲染，因为window没有被锁住了，就可以rgba数据 ----> 字节对齐 渲染
    // 填充[window_buffer]  画面就出来了  ==== 【目标 window_buffer】
    uint8_t *dst_data = static_cast<uint8_t *>(buffer.bits);
    int dst_lineSize = buffer.stride * 4;

    // 一行行的渲染
    for (int i = 0; i < buffer.height; ++i) {
        // 将视频数据复制到 window_buffer
        memcpy(dst_data + i * dst_lineSize, data + i * lineSize, dst_lineSize);
    }
    // 刷新显示
    ANativeWindow_unlockAndPost(window); // 解锁后 并且刷新 window_buffer的数据显示画面

    pthread_mutex_unlock(&mutex);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_boardour_ffmpegdemo_player_FFPlayer_n_1prepare(JNIEnv *env, jobject obj,
                                                        jlong nativePrt, jstring path) {
    // 视频地址
    const char *path_ = env->GetStringUTFChars(path, 0);
    // jni 回调 java层
    JNICallback *callback = new JNICallback(vm, env, obj);

    FFPlayer *player = reinterpret_cast<FFPlayer *>(nativePrt);
    // 设置视频播放路径
    player->setPath(path_);
    // 设置 java层回调监听
    player->setCallback(callback);
    player->setRenderCallback(renderCallback);
    // 开始准备工作
    player->prepare();
    env->ReleaseStringUTFChars(path, path_);

}
extern "C"
JNIEXPORT void JNICALL
Java_com_boardour_ffmpegdemo_player_FFPlayer_n_1start(JNIEnv *env, jobject thiz,
                                                      jlong nativePrt) {
    FFPlayer *player = reinterpret_cast<FFPlayer *>(nativePrt);
    if (player) {
        player->start();
    }
}
extern "C"
JNIEXPORT void JNICALL
Java_com_boardour_ffmpegdemo_player_FFPlayer_n_1stop(JNIEnv *env, jobject thiz,
                                                     jlong nativePrt) {

}
extern "C"
JNIEXPORT void JNICALL
Java_com_boardour_ffmpegdemo_player_FFPlayer_n_1release(JNIEnv *env, jobject thiz,
                                                        jlong nativePrt) {
    FFPlayer *player = reinterpret_cast<FFPlayer *>(nativePrt);
    if (player) {
        delete player;
    }
}

// 根据Surface 初始化Window
extern "C"
JNIEXPORT void JNICALL
Java_com_boardour_ffmpegdemo_player_FFPlayer_n_1surface(JNIEnv *env, jobject thiz, jlong native_prt,
                                                        jobject surface) {

    pthread_mutex_lock(&mutex);

    // 如果创建过Window ，就先释放
    if (window) {
        ANativeWindow_release(window);
        window = nullptr;
    }

    // 创建ANativeWindow 用于视频渲染
    window = ANativeWindow_fromSurface(env, surface);

    pthread_mutex_unlock(&mutex);
}